package com.xja.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xja.exception.CustomException;
import com.xja.mapper.CollectionMapper;
import com.xja.model.entity.Collection;
import com.xja.model.vo.req.CollectionReqVO;
import com.xja.model.vo.req.CollectionTestReqVO;
import com.xja.model.vo.resp.CollectionTestRespVO;
import com.xja.service.ICollectionService;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author caijg
 * @since 2025-06-10
 */
@Service
@RequiredArgsConstructor
public class CollectionServiceImpl extends ServiceImpl<CollectionMapper, Collection> implements ICollectionService {

    private final VectorStore vectorStore;

    @Override
    public Page<Collection> search(CollectionReqVO collectionReqVO) {
        // 获取请求参数
        Long pageNum = collectionReqVO.getPageNum();
        Long pageSize = collectionReqVO.getPageSize();
        String keyword = collectionReqVO.getKeyword();
        // 1.设置分页参数
        Page<Collection> p = Page.of(pageNum, pageSize);
        // 2.设置查询条件
        LambdaQueryWrapper<Collection> wrapper = this.lambdaQuery()
                .getWrapper()
                .like(StrUtil.isNotBlank(keyword), Collection::getContent, keyword);
        // 3.执行查询
        this.page(p, wrapper);
        // 4.返回分页结果
        return p;
    }

    @Override
    @Transactional
    public void add(String content) {
        if (StrUtil.isBlank(content)) {
            throw new CustomException("文档内容不可为空！", 500);
        }
        if (content.length() * 3 >= 256 * 3) {
            throw new CustomException("文档内容不可超过256个字符！", 500);
        }
        // 1.添加内容到向量数据库
        String docId = UUID.randomUUID().toString();
        List<Document> documents = List.of(new Document(docId, content, Map.of()));
        vectorStore.add(documents);
        // 2.添加内容到Mysql中
        Collection collection = new Collection(docId, content);
        this.save(collection);
    }

    @Override
    @Transactional
    public void deleteById(String id) {
        // 1.删除Mysql中的内容
        this.removeById(id);
        // 2.删除向量数据库中的内容
        vectorStore.delete(List.of(id));
    }

    @Override
    @Transactional
    public void updateCollection(Collection collection) {
        if (StrUtil.isBlank(collection.getContent())) {
            throw new CustomException("文档内容不可为空！", 500);
        }
        if (collection.getContent().length() * 3 >= 256 * 3) {
            throw new CustomException("文档内容不可超过256个字符！", 500);
        }
        // 1.修改Mysql中的内容
        this.updateById(collection);
        // 2.删除向量数据库中的内容
        vectorStore.delete(List.of(collection.getDocId()));
        // 3.添加到向量数据库
        vectorStore.add(List.of(new Document(collection.getDocId(), collection.getContent(), Map.of())));
    }

    @Override
    public List<CollectionTestRespVO> test(CollectionTestReqVO collectionTestReqVO) {
        String userInput = collectionTestReqVO.getUserInput();
        Integer topK = collectionTestReqVO.getTopK();
        Double threshold = collectionTestReqVO.getThreshold();

        List<Document> documents = vectorStore.similaritySearch(SearchRequest.builder()
                .query(userInput)
                .topK(topK)
                .similarityThreshold(threshold)
                .build());

        if (CollUtil.isEmpty(documents)) {
            return List.of();
        }
        return documents.stream()
                .map(d -> new CollectionTestRespVO(d.getId(), d.getText(), d.getScore()))
                .toList();
    }
}
